package com.guaoran.source.spring.framework.webmvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Map;

/**
 * @author : 孤傲然
 * @Description :
 * @date :2018/6/23 18:51
 */
public class HandlerAdapter {
    private Map<String,Integer> paramMapping;
    public HandlerAdapter(Map<String, Integer> paramMapping) {
        this.paramMapping = paramMapping;
    }

    /**
     * 根据方法的参数，进行动态匹配后，经过处理返回对应的ModelAndView
     * @param req
     * @param resp
     * @param handler
     */
    public ModelAndView handle(HttpServletRequest req, HttpServletResponse resp, HandlerMapping handler) throws Exception {
        //根据用户请求的参数信息，跟HandlerMapping 中存储的method中的参数信息进行动态匹配
        //req、resp 存进来的目的：因为controller中的method中可以对request和response进行赋值，传进来的目的就是透传

        //1.要拿到这个方法的形参列表
        Class<?>[] parameterTypes = handler.getMethod().getParameterTypes();

        //2.拿到自定义命名的参数所在位置,用户通过url传过来的参数
        Map<String,String[]> reqParameterMap = req.getParameterMap();

        //3.构造实参列表
        Object[] paramValues = new Object[parameterTypes.length];
        //遍历用户传过来的参数，将值保存到实参列表中
        for (Map.Entry<String, String[]> param :reqParameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue()).replaceAll("\\[||\\]","").replaceAll("\\s","");
            if (!this.paramMapping.containsKey(param.getKey())) {continue;}
            //从方法的各个参数中，根据当前参数的参数名称，找到对应参数所在方法中的下标位置，根据下标位置，构造实参列表
            int index = paramMapping.get(param.getKey());
            paramValues[index] = convertParamValue(value,parameterTypes[index]);
        }
        if(this.paramMapping.containsKey(HttpServletRequest.class.getName())){
            int reqIndex = this.paramMapping.get(HttpServletRequest.class.getName());
            paramValues[reqIndex] = req;
        }
        if(this.paramMapping.containsKey(HttpServletResponse.class.getName())){
            int respIndex = this.paramMapping.get(HttpServletResponse.class.getName());
            paramValues[respIndex] = resp;
        }
        //4.从handler中取出controller，method，利用反射调用
        Object result = handler.getMethod().invoke(handler.getController(),paramValues);
        if(result == null){return null;}

        //只有当用来传过来的ModelAndView为空时，才会new一个默认的ModelAndView
        if(handler.getMethod().getReturnType()==ModelAndView.class){
            return (ModelAndView) result;
        }
        return null;
    }
    //转换参数
    private Object convertParamValue(String value,Class<?> clazz){
        if(clazz == Integer.class){
            return Integer.valueOf(value);
        }else if(clazz == int.class){
            return Integer.valueOf(value).intValue();
        }else{
            return value;
        }
    }
}

